﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using XoLib.Generic;

namespace XoLib.Manager
{

    /// <summary>
    ///   GenericRegistrator
    /// </summary>
    public abstract class TypeRegistrator<V> : Singleton<V>, IRegistrator where V : new()
    {
        /// <summary>
        ///   Interface for register class
        /// </summary>
        public interface IGenericType
        {
            /// <summary>
            ///   Register
            /// </summary>
            void InsertIn(V reg, Type ClassType);
        }

        /// <summary>
        ///  Store All type
        /// </summary>
        private readonly Dictionary<Type, Dictionary<ushort, Type>> DicClass = new Dictionary<Type, Dictionary<ushort, Type>>();

       
        /// <summary>
        /// <para>
        /// <param name="key">string</param>
        /// <param name="Code">ushort</param>
        /// <param name="store">Type</param>
        /// </para>
        ///   TryGetValue
        ///   <returns>bool</returns>
        /// </summary>
        public bool TryGetValue(Type key, ushort Code, out Type store)
        {
            Dictionary<ushort, Type> dic = null;

            if (!DicClass.TryGetValue(key, out dic))
            {
                store = default(Type);
                return false;
            }
            return dic.TryGetValue(Code, out store);
        }

        /// <summary>
        /// <para>
        /// <param name="key">string</param>
        /// <param name="Code">ushort</param>
        /// <param name="store">Type</param>
        /// </para>
        ///   SetValue
        ///   <returns>bool</returns>
        /// </summary>
        public bool SetValue(Type key, ushort Code, Type store)
        {

            Dictionary<ushort, Type> dic = null;

            if (!DicClass.TryGetValue(key, out dic))
                DicClass.Add(key, new Dictionary<ushort, Type>());

            if (!DicClass.TryGetValue(key, out dic))
                return false;

            DicClass[key].Add(Code, store);

            return true;
        }


        /// <summary>
        /// <para>
        /// <param name="key">string</param>
        /// <param name="Code">ushort</param>
        /// </para>
        ///   GetValue U
        /// <returns>U</returns>
        /// </summary>
        public U GetValue<U>(Type key, ushort Code)
        {
            Type store;
            if (!TryGetValue(key, Code, out store))
            {
                return default(U);
            }

            if (!typeof(U).IsAssignableFrom(store))
            {
                return default(U);
            }

            return (U)Activator.CreateInstance(store);
        }

        /// <summary>
        /// <para>
        /// <param name="ClassType">Type</param>
        /// </para>
        ///   Register Class IClass
        /// </summary>
        public void RegisterClass<U>(Type ClassType) where U : IGenericType
        {
            var attributes = ClassType.GetCustomAttributes(typeof(U), false);
            if (attributes.Length == 1)
            {
                ((U)attributes[0]).InsertIn(Instance, ClassType);
            }
            else
                return;
        }

        /// <summary>
        /// <para>
        /// <param name="ClassTypes">Type[]</param>
        /// </para>
        ///   Register Class IClass
        /// </summary>
        public void RegisterClass<U>(Type[] ClassTypes) where U : IGenericType
        {
            foreach (Type pType in ClassTypes)
            {
                RegisterClass<U>(pType);
            }
        }

    }
}
